﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;

namespace lumo.input
{
    /// <summary>
    /// Wrapper for input objects.
    /// </summary>
    public class InputWrapper : IInputObject
    {
        private bool LastDown = false;
        private bool CurrentDown = false;
        private float RepeatCount = 0;
        private float _RepeatDelay = Config.DefaultRepeatDelay;
        private float _RepeatTime = Config.DefaultRepeatTime;

        private List<IInputObject> InputObjectList = new List<IInputObject>();
        private List<IInputObject> InputUpdateList = new List<IInputObject>();

        // The propertie for frame ID
        private uint _FrameID = 0;
        /// <summary>Access for FrameID</summary>
        public uint FrameID { get { return _FrameID; } }

        /// <summary>
        /// Constructor.
        /// </summary>
        public InputWrapper()
        {
            Repeated = false;
        }

        /// <summary>
        /// Add an object
        /// </summary>
        /// <param name="Object">Object to wrap.</param>
        /// <param name="NeedUpdate">Do you need to update this object?</param>
        public void Add(IInputObject Object, bool NeedUpdate = true)
        {
            InputObjectList.Add(Object);
            if (NeedUpdate)
                InputUpdateList.Add(Object);
            LastDown = CurrentDown = AnyPressed();
        }

        /// <summary>
        /// Clear the list
        /// </summary>
        public void Clear()
        {
            InputObjectList.Clear();
            InputUpdateList.Clear();
        }

        /// <summary>
        /// Type of object.
        /// </summary>
        /// <returns>The type of object.</returns>
        public InputType GetInputType() { return InputType.InputWrapper; }

        /// <summary>
        /// Return 0, useless ID
        /// </summary>
        /// <returns>The ID.</returns>
        public long GetInputID() { return 0; }

        /// <summary>
        /// Property to check if key is pressed.
        /// </summary>
        public bool Pressed { get { return CurrentDown; } }

        /// <summary>
        /// Property to check if key is triggered.
        /// </summary>
        public bool Triggered { get { return (CurrentDown && !LastDown); } }

        /// <summary>
        /// Property to check if key is repeated.
        /// </summary>
        public bool Repeated { get; private set; }

        /// <summary>
        /// Property to check if key is released.
        /// </summary>
        public bool Released { get { return (LastDown && !CurrentDown); } }

        /// <summary>
        /// Implemented IInputObject Released.
        /// </summary>
        /// <returns>True if the key is released.</returns>
        public float RepeatDelay { get { return _RepeatDelay; } set { _RepeatDelay = value; } }

        /// <summary>
        /// Implemented IInputObject Released.
        /// </summary>
        /// <returns>True if the key is released.</returns>
        public float RepeatTime { get { return _RepeatTime; } set { _RepeatTime = value; } }

        /// <summary>
        /// Update the Wrapper
        /// </summary>
        /// <param name="Game">The game object</param>
        public void Update(LumoComponent Game)
        {
            // Only called once per frame.
            if (_FrameID == Game.FrameID)
                return;
            _FrameID = Game.FrameID;

            // Update every key
            foreach (IInputObject obj in InputUpdateList)
                obj.Update(Game);

            // Update status
            LastDown = CurrentDown;
            CurrentDown = AnyPressed();

            //
            Repeated = false;
            if (Game == null)
            {
                Repeated = Triggered;
                return;
            }

            if (CurrentDown)
            {
                if (!LastDown)
                {
                    Repeated = true;
                    RepeatCount = _RepeatDelay;
                }
                else
                {
                    RepeatCount -= (float)Game.GameTime.ElapsedGameTime.TotalMilliseconds;
                    if (RepeatCount <= 0)
                    {
                        Repeated = true;
                        RepeatCount = _RepeatTime;
                    }
                }
            }
        }

        /// <summary>
        /// Check if any key is pressed.
        /// </summary>
        private bool AnyPressed()
        {
            // If any key is pressed
            foreach (IInputObject obj in InputObjectList)
            {
                if (obj.Pressed)
                    return true;
            }
            return false;
        }
    }
}
